/*
 * AnyOption 1.3
 *
 * kishan at hackorama dot com  www.hackorama.com JULY 2001
 *
 * + Acts as a common facade class for reading
 *   commandline options as well as options from
 *   an optionfile with delimited type value pairs
 *
 * + Handles the POSIX style single character options ( -w )
 *   as well as the newer GNU long options ( --width )
 *
 * + The option file assumes the traditional format of
 *   first character based comment lines and type value
 *   pairs with a delimiter , and flags which are not pairs
 *
 *  	# this is a coment
 *  	# next line is an option value pair
 *  	width : 100
 *     	# next line is a flag
 *      noimages
 *
 * + Supports printing out Help and Usage
 *
 * + Why not just use getopt() ?
 *
 *   getopt() Its a POSIX standard not part of ANSI-C.
 *   So it may not be available on platforms like Windows.
 *
 * + Why it is so long ?
 *
 *   The actual code which does command line parsing
 *   and option file parsing are done in  few methods.
 *   Most of the extra code are for providing a flexible
 *   common public interface to both a resourcefile and
 *   and command line supporting POSIX style and
 *   GNU long option as well as mixing of both.
 *
 * + Please see "anyoption.h" for public method descriptions
 *
 */

/* Updated Auguest 2004
 * Fix from  Michael D Peters (mpeters at sandia.gov)
 * to remove static local variables, allowing multiple instantiations
 * of the reader (for using multiple configuration files).  There is
 * an error in the destructor when using multiple instances, so you
 * cannot delete your objects (it will crash), but not calling the
 * destructor only introduces a small memory leak, so I
 * have not bothered tracking it down.
 *
 * Also updated to use modern C++ style headers, rather than
 * depricated iostream.h (it was causing my compiler problems)
*/

/*
 * Updated September 2006
 * Fix from Boyan Asenov for a bug in mixing up option indexes
 * leading to exception when mixing different options types
 */

#include "anyoption.h"

AnyOption::AnyOption()
{
    init();
}

AnyOption::AnyOption(int maxopt)
{
    init( maxopt , maxopt );
}

AnyOption::AnyOption(int maxopt, int maxcharopt)
{
    init( maxopt , maxcharopt );
}

AnyOption::~AnyOption()
{
    if ( mem_allocated )
        cleanup();
}

void
AnyOption::init()
{
    init( DEFAULT_MAXOPTS , DEFAULT_MAXOPTS );
}

void
AnyOption::init(int maxopt, int maxcharopt )
{

    max_options 	= maxopt;
    max_char_options = maxcharopt;
    max_usage_lines	= DEFAULT_MAXUSAGE;
    usage_lines	= 0 ;
    argc 		= 0;
    argv 		= NULL;
    posix_style	= true;
    verbose 	= false;
    filename 	= NULL;
    appname 	= NULL;
    option_counter 	= 0;
    optchar_counter	= 0;
    new_argv 	= NULL;
    new_argc 	= 0 ;
    max_legal_args 	= 0 ;
    command_set 	= false;
    file_set 	= false;
    values 		= NULL;
    g_value_counter = 0;
    mem_allocated 	= false;
    command_set 	= false;
    file_set	= false;
    opt_prefix_char     = '-';
    file_delimiter_char = ':';
    file_comment_char   = '#';
    equalsign 	= '=';
    comment       = '#' ;
    delimiter     = ':' ;
    endofline     = '\n';
    whitespace    = ' ' ;
    nullterminate = '\0';
    set = false;
    once = true;
    hasoptions = false;
    autousage = false;

    strcpy( long_opt_prefix , "--" );

    if ( alloc() == false )
    {
        cout << endl << "OPTIONS ERROR : Failed allocating memory" ;
        cout << endl ;
        cout << "Exiting." << endl ;
        exit (0);
    }
}

bool
AnyOption::alloc()
{
    int i = 0 ;
    int size = 0 ;

    if ( mem_allocated )
        return true;

    size = (max_options+1) * sizeof(const char*);
    options = (const char**)malloc( size );
    optiontype = (int*) malloc( (max_options+1)*sizeof(int) );
    optionindex = (int*) malloc( (max_options+1)*sizeof(int) );
    if ( options == NULL || optiontype == NULL || optionindex == NULL )
        return false;
    else
        mem_allocated  = true;
    for ( i = 0 ; i < max_options ; i++ )
    {
        options[i] = NULL;
        optiontype[i] = 0 ;
        optionindex[i] = -1 ;
    }
    optionchars = (char*) malloc( (max_char_options+1)*sizeof(char) );
    optchartype = (int*) malloc( (max_char_options+1)*sizeof(int) );
    optcharindex = (int*) malloc( (max_char_options+1)*sizeof(int) );
    if ( optionchars == NULL ||
            optchartype == NULL ||
            optcharindex == NULL )
    {
        mem_allocated = false;
        return false;
    }
    for ( i = 0 ; i < max_char_options ; i++ )
    {
        optionchars[i] = '0';
        optchartype[i] = 0 ;
        optcharindex[i] = -1 ;
    }

    size = (max_usage_lines+1) * sizeof(const char*) ;
    usage = (const char**) malloc( size );

    if ( usage == NULL  )
    {
        mem_allocated = false;
        return false;
    }
    for ( i = 0 ; i < max_usage_lines ; i++ )
        usage[i] = NULL;

    return true;
}

bool
AnyOption::doubleOptStorage()
{
    options = (const char**)realloc( options,
                                     ((2*max_options)+1) * sizeof( const char*) );
    optiontype = (int*) realloc(  optiontype ,
                                  ((2 * max_options)+1)* sizeof(int) );
    optionindex = (int*) realloc(  optionindex,
                                   ((2 * max_options)+1) * sizeof(int) );
    if ( options == NULL || optiontype == NULL || optionindex == NULL )
        return false;
    /* init new storage */
    for ( int i = max_options ; i < 2*max_options ; i++ )
    {
        options[i] = NULL;
        optiontype[i] = 0 ;
        optionindex[i] = -1 ;
    }
    max_options = 2 * max_options ;
    return true;
}

bool
AnyOption::doubleCharStorage()
{
    optionchars = (char*) realloc( optionchars,
                                   ((2*max_char_options)+1)*sizeof(char) );
    optchartype = (int*) realloc( optchartype,
                                  ((2*max_char_options)+1)*sizeof(int) );
    optcharindex = (int*) realloc( optcharindex,
                                   ((2*max_char_options)+1)*sizeof(int) );
    if ( optionchars == NULL ||
            optchartype == NULL ||
            optcharindex == NULL )
        return false;
    /* init new storage */
    for ( int i = max_char_options ; i < 2*max_char_options ; i++ )
    {
        optionchars[i] = '0';
        optchartype[i] = 0 ;
        optcharindex[i] = -1 ;
    }
    max_char_options = 2 * max_char_options;
    return true;
}

bool
AnyOption::doubleUsageStorage()
{
    usage = (const char**)realloc( usage,
                                   ((2*max_usage_lines)+1) * sizeof( const char*) );
    if ( usage == NULL )
        return false;
    for ( int i = max_usage_lines ; i < 2*max_usage_lines ; i++ )
        usage[i] = NULL;
    max_usage_lines = 2 * max_usage_lines ;
    return true;

}


void
AnyOption::cleanup()
{
    free (options);
    free (optiontype);
    free (optionindex);
    free (optionchars);
    free (optchartype);
    free (optcharindex);
    free (usage);
    if ( values != NULL )
        free (values);
    if ( new_argv != NULL )
        free (new_argv);
}

void
AnyOption::setCommandPrefixChar( char _prefix )
{
    opt_prefix_char = _prefix;
}

void
AnyOption::setCommandLongPrefix( char *_prefix )
{
    if ( strlen( _prefix ) > MAX_LONG_PREFIX_LENGTH )
    {
        *( _prefix + MAX_LONG_PREFIX_LENGTH ) = '\0';
    }

    strcpy (long_opt_prefix,  _prefix);
}

void
AnyOption::setFileCommentChar( char _comment )
{
    file_delimiter_char = _comment;
}


void
AnyOption::setFileDelimiterChar( char _delimiter )
{
    file_comment_char = _delimiter ;
}

bool
AnyOption::CommandSet()
{
    return( command_set );
}

bool
AnyOption::FileSet()
{
    return( file_set );
}

void
AnyOption::noPOSIX()
{
    posix_style = false;
}

bool
AnyOption::POSIX()
{
    return posix_style;
}


void
AnyOption::setVerbose()
{
    verbose = true ;
}

void
AnyOption::printVerbose()
{
    if ( verbose )
        cout << endl  ;
}
void
AnyOption::printVerbose( const char *msg )
{
    if ( verbose )
        cout << msg  ;
}

void
AnyOption::printVerbose( char *msg )
{
    if ( verbose )
        cout << msg  ;
}

void
AnyOption::printVerbose( char ch )
{
    if ( verbose )
        cout << ch ;
}

bool
AnyOption::hasOptions()
{
    return hasoptions;
}

void
AnyOption::autoUsagePrint(bool _autousage)
{
    autousage = _autousage;
}

void
AnyOption::useCommandArgs( int _argc, char **_argv )
{
    argc = _argc;
    argv = _argv;
    command_set = true;
    appname = argv[0];
    if (argc > 1) hasoptions = true;
}

void
AnyOption::useFiileName( const char *_filename )
{
    filename = _filename;
    file_set = true;
}

/*
 * set methods for options
 */

void
AnyOption::setCommandOption( const char *opt )
{
    addOption( opt , COMMAND_OPT );
    g_value_counter++;
}

void
AnyOption::setCommandOption( char opt )
{
    addOption( opt , COMMAND_OPT );
    g_value_counter++;
}

void
AnyOption::setCommandOption( const char *opt , char optchar )
{
    addOption( opt , COMMAND_OPT );
    addOption( optchar , COMMAND_OPT );
    g_value_counter++;
}

void
AnyOption::setCommandFlag( const char *opt )
{
    addOption( opt , COMMAND_FLAG );
    g_value_counter++;
}

void
AnyOption::setCommandFlag( char opt )
{
    addOption( opt , COMMAND_FLAG );
    g_value_counter++;
}

void
AnyOption::setCommandFlag( const char *opt , char optchar )
{
    addOption( opt , COMMAND_FLAG );
    addOption( optchar , COMMAND_FLAG );
    g_value_counter++;
}

void
AnyOption::setFileOption( const char *opt )
{
    addOption( opt , FILE_OPT );
    g_value_counter++;
}

void
AnyOption::setFileOption( char opt )
{
    addOption( opt , FILE_OPT );
    g_value_counter++;
}

void
AnyOption::setFileOption( const char *opt , char optchar )
{
    addOption( opt , FILE_OPT );
    addOption( optchar, FILE_OPT  );
    g_value_counter++;
}

void
AnyOption::setFileFlag( const char *opt )
{
    addOption( opt , FILE_FLAG );
    g_value_counter++;
}

void
AnyOption::setFileFlag( char opt )
{
    addOption( opt , FILE_FLAG );
    g_value_counter++;
}

void
AnyOption::setFileFlag( const char *opt , char optchar )
{
    addOption( opt , FILE_FLAG );
    addOption( optchar , FILE_FLAG );
    g_value_counter++;
}

void
AnyOption::setOption( const char *opt )
{
    addOption( opt , COMMON_OPT );
    g_value_counter++;
}

void
AnyOption::setOption( char opt )
{
    addOption( opt , COMMON_OPT );
    g_value_counter++;
}

void
AnyOption::setOption( const char *opt , char optchar )
{
    addOption( opt , COMMON_OPT );
    addOption( optchar , COMMON_OPT );
    g_value_counter++;
}

void
AnyOption::setFlag( const char *opt )
{
    addOption( opt , COMMON_FLAG );
    g_value_counter++;
}

void
AnyOption::setFlag( const char opt )
{
    addOption( opt , COMMON_FLAG );
    g_value_counter++;
}

void
AnyOption::setFlag( const char *opt , char optchar )
{
    addOption( opt , COMMON_FLAG );
    addOption( optchar , COMMON_FLAG );
    g_value_counter++;
}

void
AnyOption::addOption( const char *opt, int type )
{
    if ( option_counter >= max_options )
    {
        if ( doubleOptStorage() == false )
        {
            addOptionError( opt );
            return;
        }
    }
    options[ option_counter ] = opt ;
    optiontype[ option_counter ] =  type ;
    optionindex[ option_counter ] = g_value_counter;
    option_counter++;
}

void
AnyOption::addOption( char opt, int type )
{
    if ( !POSIX() )
    {
        printVerbose("Ignoring the option character \"");
        printVerbose(  opt );
        printVerbose( "\" ( POSIX options are turned off )" );
        printVerbose();
        return;
    }


    if ( optchar_counter >= max_char_options )
    {
        if ( doubleCharStorage() == false )
        {
            addOptionError( opt );
            return;
        }
    }
    optionchars[ optchar_counter ] =  opt ;
    optchartype[ optchar_counter ] =  type ;
    optcharindex[ optchar_counter ] = g_value_counter;
    optchar_counter++;
}

void
AnyOption::addOptionError( const char *opt )
{
    cout << endl ;
    cout << "OPTIONS ERROR : Failed allocating extra memory " << endl ;
    cout << "While adding the option : \""<< opt << "\"" << endl;
    cout << "Exiting." << endl ;
    cout << endl ;
    exit(0);
}

void
AnyOption::addOptionError( char opt )
{
    cout << endl ;
    cout << "OPTIONS ERROR : Failed allocating extra memory " << endl ;
    cout << "While adding the option: \""<< opt << "\"" << endl;
    cout << "Exiting." << endl ;
    cout << endl ;
    exit(0);
}

void
AnyOption::processOptions()
{
    if ( ! valueStoreOK() )
        return;
}

void
AnyOption::processCommandArgs(int max_args)
{
    max_legal_args = max_args;
    processCommandArgs();
}

void
AnyOption::processCommandArgs( int _argc, char **_argv, int max_args )
{
    max_legal_args = max_args;
    processCommandArgs(  _argc, _argv );
}

void
AnyOption::processCommandArgs( int _argc, char **_argv )
{
    useCommandArgs( _argc, _argv );
    processCommandArgs();
}

void
AnyOption::processCommandArgs()
{
    if ( ! ( valueStoreOK() && CommandSet() )  )
        return;

    if ( max_legal_args == 0 )
        max_legal_args = argc;
    new_argv = (int*) malloc( (max_legal_args+1) * sizeof(int) );
    for ( int i = 1 ; i < argc ; i++ ) /* ignore first argv */
    {
        if (  argv[i][0] == long_opt_prefix[0] &&
                argv[i][1] == long_opt_prefix[1] )   /* long GNU option */
        {
            int match_at = parseGNU( argv[i]+2 ); /* skip -- */
            if ( match_at >= 0 && i < argc-1 ) /* found match */
                setValue( options[match_at] , argv[++i] );
        }
        else if (  argv[i][0] ==  opt_prefix_char )  /* POSIX char */
        {
            if ( POSIX() )
            {
                char ch =  parsePOSIX( argv[i]+1 );/* skip - */
                if ( ch != '0' && i < argc-1 ) /* matching char */
                    setValue( ch ,  argv[++i] );
            }
            else   /* treat it as GNU option with a - */
            {
                int match_at = parseGNU( argv[i]+1 ); /* skip - */
                if ( match_at >= 0 && i < argc-1 ) /* found match */
                    setValue( options[match_at] , argv[++i] );
            }
        }
        else   /* not option but an argument keep index */
        {
            if ( new_argc < max_legal_args )
            {
                new_argv[ new_argc ] = i ;
                new_argc++;
            }
            else  /* ignore extra arguments */
            {
                printVerbose( "Ignoring extra argument: " );
                printVerbose( argv[i] );
                printVerbose( );
                printAutoUsage();
            }
            printVerbose( "Unknown command argument option : " );
            printVerbose( argv[i] );
            printVerbose( );
            printAutoUsage();
        }
    }
}

char
AnyOption::parsePOSIX( char* arg )
{

    for ( unsigned int i = 0 ; i < strlen(arg) ; i++ )
    {
        char ch = arg[i] ;
        if ( matchChar(ch) )  /* keep matching flags till an option */
        {
            /*if last char argv[++i] is the value */
            if ( i == strlen(arg)-1 )
            {
                return ch;
            }
            else /* else the rest of arg is the value */
            {
                i++; /* skip any '=' and ' ' */
                while ( arg[i] == whitespace
                        || arg[i] == equalsign )
                    i++;
                setValue( ch , arg+i );
                return '0';
            }
        }
    }
    printVerbose( "Unknown command argument option : " );
    printVerbose( arg );
    printVerbose( );
    printAutoUsage();
    return '0';
}

int
AnyOption::parseGNU( char *arg )
{
    int split_at = 0;
    /* if has a '=' sign get value */
    for ( unsigned int i = 0 ; i < strlen(arg) ; i++ )
    {
        if (arg[i] ==  equalsign )
        {
            split_at = i ; /* store index */
            i = strlen(arg); /* get out of loop */
        }
    }
    if ( split_at > 0 ) /* it is an option value pair */
    {
        char* tmp = (char*) malloc(  (split_at+1)*sizeof(char) );
        for ( int i = 0 ; i < split_at ; i++ )
            tmp[i] = arg[i];
        tmp[split_at] = '\0';

        if ( matchOpt( tmp ) >= 0 )
        {
            setValue( options[matchOpt(tmp)] , arg+split_at+1 );
            free (tmp);
        }
        else
        {
            printVerbose( "Unknown command argument option : " );
            printVerbose( arg );
            printVerbose( );
            printAutoUsage();
            free (tmp);
            return -1;
        }
    }
    else  /* regular options with no '=' sign  */
    {
        return  matchOpt(arg);
    }
    return -1;
}


int
AnyOption::matchOpt( char *opt )
{
    for ( int i = 0 ; i < option_counter ; i++ )
    {
        if ( strcmp( options[i], opt ) == 0 )
        {
            if ( optiontype[i] ==  COMMON_OPT ||
                    optiontype[i] ==  COMMAND_OPT )
            {
                /* found option return index */
                return i;
            }
            else if ( optiontype[i] == COMMON_FLAG ||
                      optiontype[i] == COMMAND_FLAG )
            {
                /* found flag, set it */
                setFlagOn( opt );
                return -1;
            }
        }
    }
    printVerbose( "Unknown command argument option : " );
    printVerbose( opt  ) ;
    printVerbose( );
    printAutoUsage();
    return  -1;
}
bool
AnyOption::matchChar( char c )
{
    for ( int i = 0 ; i < optchar_counter ; i++ )
    {
        if ( optionchars[i] == c )  /* found match */
        {
            if (optchartype[i] == COMMON_OPT ||
                    optchartype[i] == COMMAND_OPT )
            {
                /* an option store and stop scanning */
                return true;
            }
            else if ( optchartype[i] == COMMON_FLAG ||
                      optchartype[i] == COMMAND_FLAG )   /* a flag store and keep scanning */
            {
                setFlagOn( c );
                return false;
            }
        }
    }
    printVerbose( "Unknown command argument option : " );
    printVerbose( c ) ;
    printVerbose( );
    printAutoUsage();
    return false;
}

bool
AnyOption::valueStoreOK( )
{
    int size= 0;
    if ( !set )
    {
        if ( g_value_counter > 0 )
        {
            size = g_value_counter * sizeof(char*);
            values = (char**)malloc( size );
            for ( int i = 0 ; i < g_value_counter ; i++)
                values[i] = NULL;
            set = true;
        }
    }
    return  set;
}

/*
 * public get methods
 */
char*
AnyOption::getValue( const char *option )
{
    if ( !valueStoreOK() )
        return NULL;

    for ( int i = 0 ; i < option_counter ; i++ )
    {
        if ( strcmp( options[i], option ) == 0 )
            return values[ optionindex[i] ];
    }
    return NULL;
}

bool
AnyOption::getFlag( const char *option )
{
    if ( !valueStoreOK() )
        return false;
    for ( int i = 0 ; i < option_counter ; i++ )
    {
        if ( strcmp( options[i], option ) == 0 )
            return findFlag( values[ optionindex[i] ] );
    }
    return false;
}

char*
AnyOption::getValue( char option )
{
    if ( !valueStoreOK() )
        return NULL;
    for ( int i = 0 ; i < optchar_counter ; i++ )
    {
        if ( optionchars[i] == option )
            return values[ optcharindex[i] ];
    }
    return NULL;
}

bool
AnyOption::getFlag( char option )
{
    if ( !valueStoreOK() )
        return false;
    for ( int i = 0 ; i < optchar_counter ; i++ )
    {
        if ( optionchars[i] == option )
            return findFlag( values[ optcharindex[i] ] ) ;
    }
    return false;
}

bool
AnyOption::findFlag( char* val )
{
    if ( val == NULL )
        return false;

    if ( strcmp( TRUE_FLAG , val ) == 0 )
        return true;

    return false;
}

/*
 * private set methods
 */
bool
AnyOption::setValue( const char *option , char *value )
{
    if ( !valueStoreOK() )
        return false;
    for ( int i = 0 ; i < option_counter ; i++ )
    {
        if ( strcmp( options[i], option ) == 0 )
        {
            values[ optionindex[i] ] = (char*) malloc((strlen(value)+1)*sizeof(char));
            strcpy( values[ optionindex[i] ], value );
            return true;
        }
    }
    return false;
}

bool
AnyOption::setFlagOn( const char *option )
{
    if ( !valueStoreOK() )
        return false;
    for ( int i = 0 ; i < option_counter ; i++ )
    {
        if ( strcmp( options[i], option ) == 0 )
        {
            values[ optionindex[i] ] = (char*) malloc((strlen(TRUE_FLAG)+1)*sizeof(char));
            strcpy( values[ optionindex[i] ]  ,  TRUE_FLAG );
            return true;
        }
    }
    return false;
}

bool
AnyOption::setValue( char option , char *value )
{
    if ( !valueStoreOK() )
        return false;
    for ( int i = 0 ; i < optchar_counter ; i++ )
    {
        if ( optionchars[i] == option )
        {
            values[ optcharindex[i] ] = (char*) malloc((strlen(value)+1)*sizeof(char));
            strcpy( values[ optcharindex[i] ],  value );
            return true;
        }
    }
    return false;
}

bool
AnyOption::setFlagOn( char option )
{
    if ( !valueStoreOK() )
        return false;
    for ( int i = 0 ; i < optchar_counter ; i++ )
    {
        if ( optionchars[i] == option )
        {
            values[ optcharindex[i] ] = (char*) malloc((strlen(TRUE_FLAG)+1)*sizeof(char));
            strcpy( values[ optcharindex[i] ] , TRUE_FLAG );
            return true;
        }
    }
    return false;
}


int
AnyOption::getArgc( )
{
    return new_argc;
}

char*
AnyOption::getArgv( int index )
{
    if ( index < new_argc )
    {
        return ( argv[ new_argv[ index ] ] );
    }
    return NULL;
}

/* dotfile sub routines */

bool
AnyOption::processFile()
{
    if ( ! (valueStoreOK() && FileSet())  )
        return false;
    return  ( consumeFile(readFile()) );
}

bool
AnyOption::processFile( const char *filename )
{
    useFiileName(filename );
    return ( processFile() );
}

char*
AnyOption::readFile()
{
    return ( readFile(filename) );
}

/*
 * read the file contents to a character buffer
 */

char*
AnyOption::readFile( const char* fname )
{
    int length;
    char *buffer;
    ifstream is;
    is.open ( fname , ifstream::in );
    if ( ! is.good() )
    {
        is.close();
        return NULL;
    }
    is.seekg (0, ios::end);
    length = is.tellg();
    is.seekg (0, ios::beg);
    buffer = (char*) malloc(length*sizeof(char));
    is.read (buffer,length);
    is.close();
    return buffer;
}

/*
 * scans a char* buffer for lines that does not
 * start with the specified comment character.
 */
bool
AnyOption::consumeFile( char *buffer )
{

    if ( buffer == NULL )
        return false;

    char *cursor = buffer;/* preserve the ptr */
    char *pline = NULL ;
    int linelength = 0;
    bool newline = true;
    for ( unsigned int i = 0 ; i < strlen( buffer ) ; i++ )
    {
        if ( *cursor == endofline )  /* end of line */
        {
            if ( pline != NULL ) /* valid line */
                processLine( pline, linelength );
            pline = NULL;
            newline = true;
        }
        else if ( newline ) /* start of line */
        {
            newline = false;
            if ( (*cursor != comment ) ) /* not a comment */
            {
                pline = cursor ;
                linelength = 0 ;
            }
        }
        cursor++; /* keep moving */
        linelength++;
    }
    free (buffer);
    return true;
}


/*
 *  find a valid type value pair separated by a delimiter
 *  character and pass it to valuePairs()
 *  any line which is not valid will be considered a value
 *  and will get passed on to justValue()
 *
 *  assuming delimiter is ':' the behaviour will be,
 *
 *  width:10    - valid pair valuePairs( width, 10 );
 *  width : 10  - valid pair valuepairs( width, 10 );
 *
 *  ::::        - not valid
 *  width       - not valid
 *  :10         - not valid
 *  width:      - not valid
 *  ::          - not valid
 *  :           - not valid
 *
 */

void
AnyOption::processLine( char *theline, int length  )
{
    bool found = false;
    char *pline = (char*) malloc( (length+1)*sizeof(char) );
    for ( int i = 0 ; i < length ; i ++ )
        pline[i]= *(theline++);
    pline[length] = nullterminate;
    char *cursor = pline ; /* preserve the ptr */
    if ( *cursor == delimiter || *(cursor+length-1) == delimiter )
    {
        justValue( pline );/* line with start/end delimiter */
    }
    else
    {
        for ( int i = 1 ; i < length-1 && !found ; i++) /* delimiter */
        {
            if ( *cursor == delimiter )
            {
                *(cursor-1) = nullterminate; /* two strings */
                found = true;
                valuePairs( pline , cursor+1 );
            }
            cursor++;
        }
        cursor++;
        if ( !found ) /* not a pair */
            justValue( pline );
    }
    free (pline);
}

/*
 * removes trailing and preceeding whitespaces from a string
 */
char*
AnyOption::chomp( char *str )
{
    while ( *str == whitespace )
        str++;
    char *end = str+strlen(str)-1;
    while ( *end == whitespace )
        end--;
    *(end+1) = nullterminate;
    return str;
}

void
AnyOption::valuePairs( char *type, char *value )
{
    if ( strlen(chomp(type)) == 1  )  /* this is a char option */
    {
        for ( int i = 0 ; i < optchar_counter ; i++ )
        {
            if (  optionchars[i] == type[0]  ) /* match */
            {
                if ( optchartype[i] == COMMON_OPT ||
                        optchartype[i] == FILE_OPT )
                {
                    setValue( type[0] , chomp(value) );
                    return;
                }
            }
        }
    }
    /* if no char options matched */
    for ( int i = 0 ; i < option_counter ; i++ )
    {
        if ( strcmp( options[i], type ) == 0 ) /* match */
        {
            if ( optiontype[i] == COMMON_OPT ||
                    optiontype[i] == FILE_OPT )
            {
                setValue( type , chomp(value) );
                return;
            }
        }
    }
    printVerbose( "Unknown option in resourcefile : " );
    printVerbose( type );
    printVerbose( );
}

void
AnyOption::justValue( char *type )
{

    if ( strlen(chomp(type)) == 1  )  /* this is a char option */
    {
        for ( int i = 0 ; i < optchar_counter ; i++ )
        {
            if (  optionchars[i] == type[0]  ) /* match */
            {
                if ( optchartype[i] == COMMON_FLAG ||
                        optchartype[i] == FILE_FLAG )
                {
                    setFlagOn( type[0] );
                    return;
                }
            }
        }
    }
    /* if no char options matched */
    for ( int i = 0 ; i < option_counter ; i++ )
    {
        if ( strcmp( options[i], type ) == 0 ) /* match */
        {
            if ( optiontype[i] == COMMON_FLAG ||
                    optiontype[i] == FILE_FLAG )
            {
                setFlagOn( type );
                return;
            }
        }
    }
    printVerbose( "Unknown option in resourcefile : " );
    printVerbose( type  );
    printVerbose( );
}

/*
 * usage and help
 */


void
AnyOption::printAutoUsage()
{
    if ( autousage ) printUsage();
}

void
AnyOption::printUsage()
{

    if ( once )
    {
        once = false ;
        cout << endl ;
        for ( int i = 0 ; i < usage_lines ; i++ )
            cout << usage[i] << endl ;
        cout << endl ;
    }
}


void
AnyOption::addUsage( const char *line )
{
    if ( usage_lines >= max_usage_lines )
    {
        if ( doubleUsageStorage() == false )
        {
            addUsageError( line );
            exit(1);
        }
    }
    usage[ usage_lines ] = line ;
    usage_lines++;
}

void
AnyOption::addUsageError( const char *line )
{
    cout << endl ;
    cout << "OPTIONS ERROR : Failed allocating extra memory " << endl ;
    cout << "While adding the usage/help  : \""<< line << "\"" << endl;
    cout << "Exiting." << endl ;
    cout << endl ;
    exit(0);

}
